/*
** myhttp.c
** by Matt Rucker
** Created: Jul 25, 2013
** Last modified: Jul 26, 2013 
*/

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<errno.h>
#include<string.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<netdb.h>
#include<sys/wait.h>
#include<signal.h>

#define DEFAULTPORT 3337
#define BACKLOG 10
#define INITIAL_SIZE 64
#define MAXRECVLEN 1024

struct Buffer {
    char* data;
    int next;
    size_t size;
};

void reserve_space(struct Buffer* b, size_t bytes);
void serialize_str(char* x, struct Buffer* b);
void serialize_char(char x, struct Buffer* b);
struct Buffer* new_buffer();
void sigchld_handler(int s);

int main( int argc, char * argv[] ) {

    char* filename;
    char* token;
    char recv_buf[MAXRECVLEN];
    int sockfd, new_fd ;
    int their_port; 
    struct sockaddr_in my_addr; 
    struct sockaddr_in their_addr ; 
    struct hostent *he ; 
    struct Buffer* buf = new_buffer();
    int bytes_recv, bytes_sent;
    int addr_len; 
    int i;
    int sin_size;
    struct sigaction sa;
    int yes=1;

    // create socket
	if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1 ) {
		perror("socket") ;
		exit(1) ;
	}
	
	// initialize my address
    my_addr.sin_family = AF_INET ;
    my_addr.sin_port = htons(DEFAULTPORT);
    my_addr.sin_addr.s_addr = INADDR_ANY ;
    memset(&(my_addr.sin_zero),'\0',8) ;
    
    // set socket option
    if (setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&yes,
      sizeof(int)) == -1) {
        perror("setsockopt");
        exit(1);
    }

    // bind socket
    if (bind(sockfd, (struct sockaddr *)&my_addr, 
      sizeof(struct sockaddr)) == -1 ) {
        perror("bind") ;
        exit(1) ;
    }

    // listen for connection on socket
    if (listen(sockfd, BACKLOG) == -1) {
        perror("listen");
        exit(1);
    }
    
    // reap all dead processes (added from beej's guide)
    sa.sa_handler = sigchld_handler;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = SA_RESTART;
    if (sigaction(SIGCHLD, &sa, NULL) == -1) {
        perror("sigaction");
        exit(1);
    }
    
    // accept loop
    while(1){
        sin_size = sizeof(struct sockaddr_in);
        if (new_fd = accept(sockfd, (struct sockaddr *)&their_addr,
          &sin_size) == -1) {
            perror("accept");
            continue;
        }
        printf("server: got connection from %s\n",
          inet_ntoa(their_addr.sin_addr));
        
        // distinguish between child and parent
        if (!fork()) {
            close(sockfd);
            if (bytes_recv = recv(sockfd, recv_buf, MAXRECVLEN-1,
              0) == -1) {
                perror("recv");
                exit(1);  
            }
            recv_buf[bytes_recv] =  '\0';
            printf("%s\n",recv_buf);
            
            /*
            while(token = strtok(bytes_recv,' ')!=NULL) 
                printf("%s",token);
            */
            
            /*
            if (send(new_fd, "Hello, world!\n", 14, 0) == -1)
                perror("send");
            */
            close(new_fd);
            exit(0);
        }
        close(new_fd);
    }
    
	return 0 ;
}

void reserve_space(struct Buffer* b, size_t bytes) {
	while((b->next + bytes) > b->size) {
		b->data = realloc(b->data,b->size * 2);
        b->size *= 2;
	}
}

void serialize_str(char* x, struct Buffer* b) {
    reserve_space(b,strlen(x)+1);
    memcpy(((char *)b->data) + b->next,x,strlen(x)+1);
    b->next += (int)strlen(x) + 1;
}

void serialize_char(char x, struct Buffer* b) {
    reserve_space(b,1);
    memcpy(((char *)b->data) + b->next,&x,1);
    b->next += 1;
}

struct Buffer* new_buffer() {
    struct Buffer *b = malloc(sizeof(struct Buffer));
 
    b->data = malloc(INITIAL_SIZE);
    b->size = INITIAL_SIZE;
    b->next = 0;

    return b;
};

void sigchld_handler(int s){
    while(wait(NULL) > 0);
}
